package org.pojosoft.asfm.messaging
{
import org.pojosoft.asfm.Message;

/**
 * Default implementation for IMessagingService
 *
 * @author Duc Nguyen
 * @see org.pojosoft.asfm.messaging.IMessagingService
 */
public class MessagingService implements IMessagingService
{
    private var _topicSubscribersMap:Object = new Object();
    private var _eventResponderMap:Object = new Object();
    private var _requestQueues:Object = new Object();
    private static var _queueId:int = 0;
    private static var _messagingService:MessagingService = new MessagingService();

    public function MessagingService()
    {
        if (_messagingService != null)
        {
            throw new Error("MessagingService can only be accessed through MessagingService.newInstance()");
        }
    }

    public static function getInstance():MessagingService {
        return _messagingService;
    }

    public function publish(topic:String, msg:Message):void {
        var subscribers:Array = _topicSubscribersMap[topic];
        if (subscribers != null) {
            for (var i:int = 0; i < subscribers.length; i++) {
                var subscriber:IMessageHandler = subscribers[i];
                subscriber.onMsg(msg);
            }
            //				for (var key:String in subscribers) {
            //					var subscriber:IMessageHandler = subscribers[key];
            //					subscriber.onEvent(msg);
            //				}
        }
    }

    public function subscribe(topic:String, subscriber:IMessageHandler):void {
        var subscribers:Array = _topicSubscribersMap[topic];
        if (subscribers != null) {
            if (subscribers.indexOf(subscriber) == -1) {
                subscribers.push(subscriber);
            }
        } else {
            // create new topic and add subscriber to it
            subscribers = new Array();
            subscribers.push(subscriber);
            _topicSubscribersMap[topic] = subscribers;
        }
    }

    public function unsubscribe(topic:String, subscriber:IMessageHandler):void {
        var subscribers:Array = _topicSubscribersMap[topic];
        if (subscribers != null) {
            var index:int = subscribers.indexOf(subscriber);
            if (index > -1) {
                // remove subscriber from list
                subscribers.splice(index, 1);
                // remove array from map if its empty
                if (subscribers.length > 0) {
                    delete _topicSubscribersMap[topic];
                }
            }
        }
    }

    public function setRequestHandler(msgType:String, requestHandler:IMessageHandler):void {
        // overrides existing if exists
        _eventResponderMap[msgType] = requestHandler;
    }

    public function getRequestHandler(msgType:String):IMessageHandler {
        return _eventResponderMap[msgType];
    }

    public function request(msg:Message, resultHandler:IMessageHandler = null):void {
        // no need to setup response queue if result is not expected
        if (resultHandler != null)
        {
            // generate new queue id
            var qId:int = _queueId++;
            msg.correlationID = qId.toString();

            // save responseSubscriber for this queueId
            _requestQueues[qId.toString()] = resultHandler;
        }

        // get IEventSubscriber to this request
        var responder:IMessageHandler = _eventResponderMap[msg.type];
        if (responder == null)
            throw new Error("IMessageHandler not found for message type " + msg.type);

        responder.onMsg(msg);
    }

    public function response(msg:Message):void {
        if (msg.correlationID == null)
            throw new Error("correlationID must be specified in Message " + msg.type);

        trace("correlationId: " + msg.correlationID);
        // get responseSubscriber for this correlationId
        var responseSubscriber:IMessageHandler = _requestQueues[msg.correlationID];
        if (responseSubscriber == null)
            throw new Error("IMessageHandler not found for response correlationID " + msg.correlationID);

        responseSubscriber.onMsg(msg);
        // delete requestQueue
        delete _requestQueues[msg.correlationID];
    }

}
}